﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using Campus.Entities;
using CampusSite.Security;
using CampusSite.Support.Extensions;
using CampusSite.Models.Mail;

namespace CampusSite.Models
{
    public class UserRepository : IUserRepository
    {

        CampusSiteContext context;

        public UserRepository()
        {
            context = new CampusSiteContext();
        }
        
        public UserRepository(CampusSiteContext context)
        {
            this.context = context;
        }  

        public IQueryable<User> All
        {
            get { return context.Users; }
        }

        public IQueryable<User> AllIncluding(params Expression<Func<User, object>>[] includeProperties)
        {
            IQueryable<User> query = context.Users;
            foreach (var includeProperty in includeProperties) {
                query = query.Include(includeProperty);
            }
            return query;
        }

        public User Find(int id)
        {
            return context.Users.Find(id);
        }

        public User FindByName(string userName)
        {
            return   (from u in context.Users.Include("Responsable")
                            where String.Compare(u.UserName, userName, StringComparison.OrdinalIgnoreCase) == 0                            
                            select u).SingleOrDefault();                       
        }

        


        public void InsertOrUpdate(User User)
        {
            if (User.UserId == default(int)) {
                // New entity
                context.Users.Add(User);
            } else {
                // Existing entity
                context.Entry(User).State = EntityState.Modified;
            }
        }

        

        public void Delete(int id)
        {
            var User = context.Users.Find(id);
            context.Users.Remove(User);
            
        }

       
        public User ValidateUser(string userName, string password)
        {
            if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
                return null;
            
            
            using (var context = new CampusSiteContext())
            {
                
                var user = (from u in context.Users
                            where String.Compare(u.UserName, userName, StringComparison.OrdinalIgnoreCase) == 0
                                  && String.Compare(u.Password, password, StringComparison.OrdinalIgnoreCase) == 0                                  
                            select u).FirstOrDefault();

                return user; 
            
            }
            
        }

        /// <summary>
        /// Verifica si el usuario tiene alguno de los roles pasado por parametro
        /// </summary>
        /// <param name="username"></param>
        /// <param name="roles"></param>
        /// <returns></returns>
        public bool IsUserInRole(string username, string[] roles)
        {
            var usuario = context.Users.Where(u => u.UserName == username && u.Confirmado && roles.Contains(u.Rol)).SingleOrDefault();

            return (usuario != null);
            //return true;
        }

        /// <summary>
        /// Verifica si el usuario tiene el rol pasado por parametro
        /// </summary>
        /// <param name="username"></param>
        /// <param name="rol"></param>
        /// <returns></returns>
        public bool IsUserInRole(string username, string rol)
        {
            try
            { 
                var usuario = context.Users.Where(u => u.UserName == username && u.Rol == rol).SingleOrDefault();
                return (usuario!=null);
            }
            catch (Exception e) 
            {
                throw;
            }
        
        }


        //public bool IsAuthenticated()
        //{
        //    return User.Identity.IsAuthenticated;

        //}
        public void Dispose()
        {
            context.Dispose();
        }

        public void Save()
        {
            context.SaveChanges();
        }


        public User CreateUser(string userName, string password, bool creadoPorAdministrador)        
        {
            Campus.Entities.User user = new Campus.Entities.User();
            user.UserName = userName;
            user.Password = password;
            User usuExiste = FindByName(user.UserName);

            if (usuExiste != null)
            {
                throw new Exception(string.Format("El usuario {0} ya existe y su estado es {1} ", usuExiste.UserName, usuExiste.Confirmado ? "Confirmado" : "No Confirmado" ));
            }

            //si el usuario se creó bien, le seteo el rol responsable.
            //TODO: Para crear el usuario administrador
            if (userName.ToLower() == "soyadmincampuscrecer@gmail.com")
            {
                user.Rol = Constantes.RolAdministrador;
                user.Confirmado = true;
            }
            else
            {

                user.Confirmado = false;
                user.Rol = Constantes.RolResponsable;
                user.FechaCreacion = DateTime.Now;
                user.CreadoPorAdministrador = creadoPorAdministrador;
            }
                
            //genero un codigo de confirmación para la validacion del email.

            byte[] bytesEncriptacion = MiRijndael.Encriptar(user.UserName);
            user.UsuarioEncriptado = StringExtensions.GetStringSeparatedByGuion(bytesEncriptacion);
            this.InsertOrUpdate(user);

            return user;            
        }

        public int CreatePasswordAleatorio()
        {
            Random r = new Random();
            int pass = r.Next(100000, int.MaxValue);
            return pass;
        }


        public User FindAsNoTracking(string nombreUsuario)
        {
            return context.Users.AsNoTracking().Where(u => String.Compare(u.UserName, nombreUsuario, StringComparison.OrdinalIgnoreCase) == 0).SingleOrDefault();
        }
    }


    public interface IUserRepository : IDisposable
    {
        IQueryable<User> All { get; }
        IQueryable<User> AllIncluding(params Expression<Func<User, object>>[] includeProperties);
        User Find(int id);
        void InsertOrUpdate(User user);
        void Delete(int id);
        void Save();
        User ValidateUser(string userName, string password);
        bool IsUserInRole(string username, string[] roles);
        bool IsUserInRole(string username, string rol);
        User FindByName(string username);
        User CreateUser(string userName, string password, bool creadoPorAdministrador);
        int CreatePasswordAleatorio();
        User FindAsNoTracking(string nombreUsuario);
    }
}